import socket
from select import poll, POLLIN, POLLOUT

# POLLIN 表示可读, POLLOUT 表示可写

# poll是一个方法


def start_udp_server(address, port):
    udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    udp_server.bind((address, port))
    # read_list = [udp_server.fileno()]
    # write_list = [sys.stdin.fileno()]
    clients = []
    while True:
        data, addr = udp_server.recvfrom(65535)
        if addr not in clients:
            clients.append(addr)

        for c in clients:
            udp_server.sendto(data, c)
        # process data
    udp_server.close()


send_queue = {

}

def start_tcp_server_with_poll(address, port):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((address, port))
    server.listen(10)

    # 保存所有客户端的描述符
    clients = {}

    # 创建pollin对象
    p = poll()
    # 注册一个对象，文件描述符
    p.register(server.fileno(), POLLIN)
    while True:
        # 返回的是一个可迭代对象（元祖）
        read_fds = p.poll()
        # fd:发生事件的描述符，ev: 发生的事件
        for fd, ev in read_fds:
            # 发生读事件
            # ev 与 变量 POLLIN 等进行与操作，判断事件是否发生
            # 若同时发生读写，则ev == POLLIN | POLLOUT
            if ev & POLLIN:
                if fd == server.fileno():
                    client, _ = server.accept()
                    # 文件描述符与连接对象关联
                    clients[client.fileno()] = client
                    # 遍历所有客户端
                    for c in clients.keys():
                        # 创建写事件
                        p.register(c, POLLOUT)

                    # 注册新的连接对象,读事件
                    p.register(client.fileno(), POLLIN)
                else:
                    # 找到文件描述符相关联的对象
                    client = clients[fd]
                    try:
                        data = client.recv(65535)
                        if not data:
                            raise ConnectionError
                    except ConnectionError:
                        client.close()
                        # 撤销
                        p.unregister(fd, POLLIN)
            # 发生写事件
            if ev & POLLOUT:
                # if fd != server.fileno():
                #     p.unregister(fd, POLLOUT)
                #     continue
                pass



import argparse
import sys

print(sys.argv)

ap = argparse.ArgumentParser()
ap.add_argument("-t", type=str, choices=("tcp", "udp"), help="to use tcp / udp", default="tcp")
ap.add_argument("-H", type=str, required=True, help="the ip address to bind")
ap.add_argument("-p", type=int, required=True, help="the port to bind")

arg = ap.parse_args(sys.argv[1:])
if arg.t == "tcp":
    start_tcp_server_with_poll(arg.H, arg.p)
else:
    start_udp_server(arg.H, arg.p)